home *** CD-ROM | disk | FTP | other *** search
Text File | 1999-04-28 | 71.2 KB | 1,428 lines |
- Secure UNIX Programming FAQ
- ---------------------------
-
- Version: 0.3
-
- Last Modified: Sun Apr 11 22:32:06 PDT 1999
-
- The master copy of this FAQ is currently kept at
-
- http://www.whitefang.com/sup/
-
- The webpage has a more spiffy version of the FAQ in html.
-
- A moderated mailing list has been setup for the discussion of
- Secure UNIX programming. You can find a copy of the announcement
- at:
-
- http://www.whitefang.com/sup/announcement.txt
-
- This FAQ is also posted to comp.security.unix (c.s.u) ,
- comp.answers , news.answers.
-
- Please do not mirror this FAQ without prior permission. Due to the
- high volume of readers I'm worried that old versions of the FAQ are
- left to grow stale, consequently receive email based on fixed
- errors/omissions.
-
- Copyright
- ---------
-
- I, Thamer Al-Herbish reserve a collective copyright on this FAQ.
- Individual contributions made to this FAQ are the intellectual
- property of the contributor.
-
- I am responsible for the validity of all information found in this
- FAQ.
-
- This FAQ may contain errors, or inaccurate material. Use it at your
- own risk. Although an effort is made to keep all the material
- presented here accurate, the contributors and maintainer of this FAQ
- will not be held responsible for any damage -- direct or indirect --
- which may result from inaccuracies.
-
- You may redistribute this document as long as you keep it in its
- current form, without any modifications. Read -- keep it up to date
- please!! :-)
-
- Introduction
- ------------
-
- This FAQ answers questions about secure programming in the UNIX
- environment. It is a guide for programmers and not administrators.
- Keep this in mind because I do not tackle any administrative issues.
- Try to read it as a guide if possible. I'm sorry it sounds like a bad
- day on jeopardy.
-
- At the risk of sounding too philosophical, this FAQ is also a call to
- arms. Over almost the last decade, a good six years, a movement took
- place where security advisories would hit mailing lists and other
- forums at astonishing speed. I think the veterans are all to familiar
- with the repetitive nature of these security advisories, and the
- small amount of literature that has been published to help avoid
- insecure programming. This text is a condensation of this movement
- and a contribution made to it, placed in a technical context to
- better serve the UNIX security community. As the Usenet phrase goes:
- "Hope this helps."
-
- Additions and Contributions
- ---------------------------
-
- The current FAQ is not complete. I will continue to work on it as I
- find time. Feel free to send in material for the Todo sections, and
- for the small notes I've left around. Also, compatibility is an issue
- I struggle with sometimes. The best I can do for some UNIX flavors is
- read man pages. Corrections/addendums for compatibility notes is
- greatly appreciated, and easily done as a collective effort. All
- contributions, comments, and criticisms can be sent to:
-
- Secure UNIX Programming FAQ <sup@whitefang.com>
-
- Please don't send them to my personal mailbox, because I can keep
- things organized better with the above e-mail address. Also please
- try to be as concise as possible. Remember I will usually quote you
- directly if you have something to add.
-
- Finally, although the contributors list is currently short, the
- material in this FAQ did not pop out of my head in a pig-flying
- fashion. Attribution is given where applicable. If you feel any of
- this is unfair to something you have published, do let me know. The
- bibliography is found at the end.
-
- Special thanks to John W. Temples, Darius Bacon, Brian Spilsbury,
- Elias Levy, who had looked at some of the drafts of past material
- that made it into this FAQ. As usual, all mistakes are mine and only
- mine.
-
- Also kudos to the people at netspace.org for hosting Bugtraq all
- these years. The archive is invaluable to my research.
-
- Table of Contents
- -----------------
-
- 1) General Questions:
- 1.1) What is a secure program?
- 1.2) What is a security hole?
- 1.3) How do I find security holes?
- 1.4) What types of attacks exist?
- 1.5) How do I fix a security hole?
-
- 2) The Flow Of Information:
- 2.1) What is the flow of information?
- 2.2) What is trust?
- 2.3) What is validation?
-
- 3) Privileges and Credentials
- 3.1) What is a privilege and a credential?
- 3.2) What is the least privilege principle?
- 3.3) How do I apply the least privilege principle safely?
-
- 4) Local Process Interaction:
- 4.1) What is process attribute inheritance? Or why should I not
- write SUID programs?
- 4.2) How can I limit access to a SUID/SGID process-image safely?
- 4.3) How do I authenticate a parent process?
- 4.4) How do I authenticate a non-parent process?
-
- 5) Accessing The File System Securely:
- 5.1) How do I avoid race condition attacks?
- 5.2) How do I create/open files safely?
-
- 6) Handling Input: [ Todo ]
- 7) Handling Resources Limits: [ Todo ]
- 8) Bibliography
- 9) List of Contributors
-
- 1) General Questions
- --------------------
-
- 1.1) What is a secure program?
- ------------------------------
-
- The simplest definition would be : a program that is capable of
- performing its task withstanding any attempts to subvert it.
- This extends to the attribute of "robustness." Most importantly
- the program should be able to perform its task without
- jeopardizing the security policies of the system it is running
- on. This is done by making sure it adheres to local security
- policies at all times. To draw an analogy, a locksmith will
- install a lock, and the home owner will decide whether or not
- he will lock the door at any given time. It is the lock smith's
- responsibility to make sure the lock performs its function of
- keeping an intruder out. It is just as much the responsibility
- of the programmer to make sure the program adheres to the local
- security policies. Thus returning to the introduction, this FAQ
- is about the programmer's responsibilities and not the
- administrator.
-
- The problem with that analogy is that when it is translated
- back into UNIX terms one thinks of an authentication program.
- By all means 'login' needs to be secure, but so do all the
- system components. To quote the U.S. Department of Defense
- Trusted Computer System Evaluation Criteria (a.k.a The Orange
- Book):
-
- "No computer system can be considered truly secure if the basic
- hardware and software mechanisms that enforce the security
- policy are themselves subject to unauthorized modification or
- subversion."
-
- Unfortunately this doesn't really help because we are sadly
- left thinking of firewalls, access control lists, persistent
- authentication systems etc. and we miss out on the other system
- components that must also be considered. So the quote can be
- re-written as such:
-
- "No computer system can be considered truly secure if the basic
- hardware and software mechanisms that _can affect_ the security
- policies are themselves subject to unauthorized modification or
- subversion."
-
- This gives us a much better view of what a secure program is,
- and places a distinction between a secure program and a
- security program. The security program enforces security
- policies; however, the secure program does not enforce any
- policies but must also co-exist with the security policies.
- This allows a much broader view of every program on the system.
- All the applications, and all the servers, and all the clients
- must be implemented securely. Granted that this approach is a
- bit extremist, it is actually quite reasonable. Programming
- securely should always be done as will be seen by some of the
- points brought up in this FAQ.
-
- Finally, to finish this definition, consider a Mail User Agent
- (MUA), such a 'pine' or 'elm.' Both have to be written securely
- because they can affect the security policies if they were not.
- In light of an advisory posted to Bugtraq (Zalewski 1999), pine
- was reported to have a security hole. Even though it is not
- enforcing security policies it still failed to adhere to them.
-
- 1.2) What is a security hole?
- -----------------------------
-
- The term is somewhat colloquial but it has been used in
- technical context enough times to warrant common usage in
- security advisories. It just means the program has a flaw that
- allows an attacker to "exploit it." Thus comes the "exploit"
- that denotes a program, or technique to take advantage of the
- flaw, or "vulnerability." The terms mentioned here will be
- found in many advisories, and in this FAQ so familiarity with
- them is essential.
-
- 1.3) How do I find security holes?
- ----------------------------------
-
- Careful auditing of source code is usually the way. One way of
- doing it is going through this FAQ in its treatment toward
- specific security holes and attempt to find them throughout the
- code in question. I will attempt to give tips toward finding a
- said security hole where applicable.
-
- However, if you really really need to find that security hole,
- disassemble the binary image of the program, grok the asm
- output into your head, run it slowly but carefully keeping
- track of registers, stacks etc -- and yes grasshopper, that is
- the One True Way.
-
- 1.4) What types of attacks exist?
- ---------------------------------
-
- There are three main types of attacks (Saltzer 1975):
-
- Unauthorized release of privileged information.
-
- Unauthorized modification of privileged information.
-
- Denial of service.
-
- The word unauthorized speaks for itself. If information can be
- read, or modified when it should not have been, security has
- been breached. A denial of service attack is any attack that
- stops a program from performing its function. When considering
- whether a program is secure from its design, provisions for
- these three attacks need to be accounted for.
-
- Obviously these attacks are aggregates of the more specific
- ones that exploit security holes. But that should give you an
- idea of what you're looking out for.
-
- 1.5) How do I fix a security hole?
- ----------------------------------
-
- Traditionally there are three approaches to fixing a security
- hole. At the risk of going slightly off topic, let us go back
- to the heyday of the SYN flood attack (daemon9 1997).
-
- SYN flooding is when a host sends out a large number of TCP/IP
- packets with an unreachable source address, and a TCP flag of
- SYN. The receiving host responds and awaits for the SYN-ACK to
- complete the three-way handshake. Since the source address is
- unreachable the receiving host never receives a response to
- complete the handshake. Instead it is left in a "half open"
- state till it times out. The problem is that there is a finite
- number of "slots" per connection received on the listening
- socket. This is because the host needs to store information in
- order to recognize the last part of the TCP three-way
- handshake. This results in a denial of service where the
- receiving host would simply stop accepting new connections till
- the bogus half-open connections timed out. They are called
- half-open connections because the handshake is never completed.
-
- Interestingly enough several different approaches were used to
- solve this problem:
-
- Cisco Systems Inc., implemented a TCP Intercept feature on its
- routers. The router would act as a transparent TCP proxy
- between the real server, and the client. When a connection
- request was made from the client, the router would complete the
- handshake for the server, and open the real connection only
- after the handshake has completed. This allowed the router to
- impose a very aggressive strategy for accepting new
- connections. It would place a threshold on the amount of
- connection requests it would handle: If the amount of half-open
- connections exceeded the threshold it would lower the timeout
- period interval, thus dropping the half-open connections
- faster. The real servers were completely shielded while the
- routers took the brunt and handled it aggressively.
-
- The OpenBSD developers implemented a work-around that caused
- old half-open TCP connections to be randomly dropped when new
- connection requests arrived on a full backlog. This allowed new
- connections to be established even with a constant SYN-flood
- taking place. The old bogus connections would be dropped at the
- behest of a new connection, legitimate or not. The randomness
- was implemented to be fair to all incoming connections.
- Although arguably with a large enough flood this technique may
- fail, it did have good results as tested by the developers.
-
- Dan Bernstein (Bernstein 1996; Schenk 1996) proposed SYN
- cookies, which would eliminate the need to store information
- per half open connection. When a connection is initiated, the
- server generates a cookie with the initial TCP packet
- information. The server would then respond with the cookie.
- When the client responded with a SYN-ACK to complete the
- handshake, the server would redo the hash, this time with the
- information taken from the recent SYN-ACK packet. This would of
- course entail decrementing the sequence numbers since they have
- been incremented in the client response. If the new hash
- matched that of the returned sequence numbers, the server would
- have completed the three-way handshake. Only the secret was
- stored, the rest of the information is gathered from the
- incoming packets during the handshake. This meant only one
- datum for all incoming connections. Thus an infinite amount of
- half open connections could exist.
-
- Three different methods were used. Cisco used a "wrapper." The
- actual UNIX system was completely unconcerned with what the
- router did and required no modification. This is good for a
- scalable solution, but does not remove the problem entirely.
- The wrapper just acts as a canvas.
-
- The OpenBSD solution was to fix the problem in the
- implementation itself. This is usually the case with most
- security holes, especially the less complicated ones.
-
- The solution presented by Dan Bernstein was more of a design
- change. The system's responses were changed, but remained
- reasonably well in conformance with the TCP standard. Some
- compromises were made however (see Schenk 1996).
-
- There is no one True Way of fixing security holes. Approach the
- problem first in the code, then design, and finally by wrapping
- it if you really must.
-
- 2) The Flow Of Information
- --------------------------
-
- Although what is presented here is a bit cross platform and not
- UNIX dependent, it is so essential that I had to put it in its own
- section.
-
- 2.1) What is the flow of information?
- -------------------------------------
-
- Every program can be considered to follow a simple design: it
- accepts input, processes it, and produces output. Input may
- come from the keyboard, a file, or the network. As long as it
- is gained from an external source that is not part of the
- program, it is considered input. Output is not necessarily
- information printed on the screen, or in a log file, it may be
- an affect like the creation of a file. The processing may be
- any work from simple arithmetic, to parsing strings.
- Mathematically speaking, at least, your program should really
- be a function taking variables and producing results. This
- cycle may happen more than once during a program's lifetime.
-
- Most programmers, for purposes of keeping things simple, will
- make assumptions about input. Particularly its format, and
- whether to apply sanity checks. There are probably entire books
- on doing this correctly: designing your program correctly,
- picking the right data formats and so on. This FAQ isn't
- interested in that aspect of processing information. Instead it
- is interested in three things: trust, validation, and acting on
- input.
-
- 2.2) What is trust?
- -------------------
-
- When trust is given to an external source of input, a program
- accepts information from it while considering the information
- valid. Secure programs need to be very untrusting and always
- validate information gained from external sources. Some
- programs, such as Dan Bernstein's 'qmail' distrust information
- gained from within. Usually trust is only given to an external
- source after it has been authenticated. Take the login program
- under UNIX. Once authenticated the user is trusted to do
- whatever he wishes to do under his own credentials. Although
- this example fails because the login program vanishes and is
- replaced by a shell, you get the idea.
-
- As a general rule: any information than an attacker can
- manipulate cannot be given trust. For example:
-
- In March 1994 Sun Microsystems released a security update for
- SunOS 4.1.x that fixed a security hole related to "/etc/utmp".
- The file acted as a database that keeps track of current users
- logged onto the system with additional information such as the
- terminal, and time of login. Certain daemons such as comsat,
- and talkd, would access the file to retrieve the terminal name
- associated with a user. The terminal name would consist of the
- path to the terminal device. The daemons would open the file
- specified by the path, and write to it. Users could modify the
- file, because it was world writable, and set arbitrary file
- names for the terminal. This resulted in potentially having the
- daemons open sensitive files while running with special
- privileges, and writing to them at the behest of the attacker.
- This is a good example of trusting information that can be
- manipulated by an attacker.
-
- 2.3) What is validation?
- ------------------------
-
- When information is received from an untrusted source it must
- be validated prior to processing it. In the case of the
- aforementioned talkd hole, the daemon should have made sure the
- path to the terminal file was indeed correct. This could have
- been done by simply checking the password database, making sure
- the ownership matched, and that the terminal path did indeed
- point to a terminal. Later in the FAQ, the concept of the least
- privilege principle is explained, and it would have worked
- wonders with the aforementioned security hole.
-
- There are several ways you can validate information depending
- on what it is supposed to be. A good place to start is by
- defining its attributes. Is it supposed to hold a file name?
- Does the file exist? Is the user allowed access to that file?
- That as mentioned previously is what the talkd daemon should
- have done. In the "Handling Input" section a security hole
- found in SSH(*) will be brought up where privileged ports could
- be bound to by normal users. In that particular case the
- function binding to a port did not properly check to make sure
- the port number was not > 1024, and as such the attacker could
- bind to privileged ports; however, the security hole entailed
- another error on the part of the program that is discussed in
- more detail in the coming section.
-
- 2.4) What do you mean by "acting on input"?
- ---------------------------------------------
-
- [ I need a more formal term for it. Unfortunately I'm lost for
- words. ]
-
- When you pass input directly to a system call, external
- program, memory copying routine etc. Basically you perform an
- operation with the aid of the information. In the
- aforementioned talkd hole the pathname read from the utmp
- database was passed to a file opening system call directly. The
- program assumed it was valid, and would not be malicious. This
- is a wrong assumption.
-
- PERL supports "tainting" (Wall, Schwartz 1992). All input
- passed from an external source is tainted unless explicitly
- untainted. Any tainted input that is passed directly to a
- system call results in an error. This method of validation is
- quite ingenious. Regardless of whether or not you are using
- PERL, the methodology is a good one to follow.
-
-
- 3) Privileges and Credentials
- -----------------------------
-
- 3.1) What are privileges and credentials?
- -----------------------------------------
-
- Every process under UNIX has three sets of credentials: Real
- credentials, effective credentials, and saved credentials. The
- credentials are split into two groups, user and group
- credentials. Additionally the process has a list of
- supplemental group credentials. The different "set*id()" system
- calls allow a process to change the values in these sets. Only
- the root user can change them arbitrarily. Non-root users are
- limited to what they may change their credentials to.
-
- It is essential to know how the system calls work on the
- credential sets (see Stevens 1992 for a more exhaustive
- reference). The following table lists each system call and what
- credential set it affects, and what credentials it will allow
- the process to change into. The credential sets are abbreviated
- with RUID standing for real user ID, EGID for effective group
- ID, SVUID for the saved user ID. ( Self explanatory really.)
-
- System Call Changes Can change to
-
- setuid RUID EUID SVUID RUID EUID SVUID
-
- setgid RGID RGID SVGID RGID RGID SVGID
-
- setreuid RUID EUID RUID EUID
-
- setregid RGID EGID RGID EGID
-
- setruid RUID RUID EUID
-
- setrgid GUID RGID EGID
-
- seteuid EUID RUID EUID
-
- setegid EGID RGID EGID
-
- Make sure you've read the man pages, and just use the table for
- reference. When changing credentials make sure you change the
- right ones.
-
- The credentials are checked by the kernel for access control. A
- process is considered privileged if its credentials give it
- access to privileged information, or privileged facilities.
- This FAQ will make use of three main privilege levels:
-
- Special User -- The root user.
-
- Normal User -- A local user without root privileges.
-
- Anonymous User -- A user that has not been authenticated,
- or logged, into the local system.
-
- The definitions above are a bit misleading without some
- elaboration. The root user is considered special because the
- kernel gives him special abilities; his access to files is not
- limited by file permissions; he can bind to privileged ports;
- he can change resource limits; he can arbitrarily change his
- own credentials lowering them to any other credential; he can
- send signals to any other process, and on some UNIX flavors
- trace any other process. Although there are some other special
- abilities the root user has, the list consisted of some of the
- more important abilities. However, on certain systems
- privileged information is accessible by non-root users. For
- example, on SCO 5.0.4 the passwd database is accessible by any
- user in group "auth." Thus non-root users in that group can
- still access privileged information. In the case of SCO 5.0.4
- it is also modifiable by users in that group. The astute reader
- will note that modifying the password database can effectively
- lead to modifying one's credentials. So keep in mind that the
- usage of special privileges in this FAQ is meant to encompass
- any user who has special abilities that are not conferred upon
- other local users. This may seem ambiguous but I hope the
- definition serves its purpose well.
-
- The normal user has been authenticated, but is regarded as
- normal without any special privileges. The traditional UNIX
- kernel itself without any augmentation will not recognize any
- user except for the root user. The special user and the normal
- user have both been authenticated, but the special user is
- recognized to have higher privileges.
-
- The anonymous user is one who has not been authenticated. It is
- very important to recognize this user when network applications
- are written. For example, consider an FTP server using the
- "anonymous" user open to everyone. In the same way consider the
- FTP client that connects to the FTP server. The client is run
- by a local "normal user," (or special user if the admin is
- nutty enough) but it is connecting to a completely anonymous
- entity. It must not give the server any special abilities on
- the local system, and allow only a set of abilities such as
- writing to a predefined file (downloading from the server).
- Indeed some advisories discussed the simplest of programs such
- as 'tar' (Tarreau 1998;Der Mouse 1998) where the tar archive
- itself could subvert the application into unauthorized
- modification of privileged information.
-
- Depending on the privilege level, the application must take
- into account what the privilege allows the entity to do.
- Consider a web server that allows clients to browse the entire
- file system under a normal user ID (or the username 'www'). The
- web server should still not allow the client to browse just any
- file or it has given away part of the normal privileges to
- every user on the net.
-
- 3.2) What is the least privilege principle?
- -------------------------------------------
-
- When an application runs with higher privileges than the source
- of input, it can prevent the occurrence of security holes by
- only using the higher privileges for specific tasks. This is
- known as the least privilege principle (Saltzer 1975), because
- the lowest privileges are used during the program's execution.
- If the attacker is able to trick the program into accomplishing
- a specific task, it will do so with his privileges.
-
- Most UNIX flavors come with a utility that allows the user to
- change his personal information. It is usually called chfn. The
- information is copied to a temporary file from the password
- database. The utility then forks a child process which executes
- an editor on the temporary copy. The user is subsequently given
- control of the editor and is free to modify the copy. Once the
- user completes modifying the copy and exits from the editor,
- the utility reads the temporary copy, performs any sanity
- checks on the input, and copies it back to the password
- database. The least privilege principle must be applied in this
- case. The child process running the editor cannot do so with
- special privileges. The editor may allow the user to run a
- shell, or open other files. chfn must revert the privilege to
- that of the user in the child process before executing the
- editor.
-
- A security hole that was reported concerning XFree86 (plaguez
- 1997) The server would run with root privileges and read any
- configuration file specified from a command line option. The
- advisory demonstrated how the shadowed password database could
- be read by pointing the server to it as its configuration file.
- Since the server ran with root privileges it could open the
- database, and would inadvertently output its contents as part
- of its error reporting. Thus an attacker could read files he
- would not normally be able to. Had the X server used the same
- privileges as the end user when attempting to read the
- configuration file, it would not have been able to. The
- attacker would only be able to access files readable by him.
- The file opening operation should have been done with the least
- privilege principle.
-
- 3.3) How do I apply the least privilege principle safely?
- ---------------------------------------------------------
-
- The least privilege principle can be applied by either lowering
- privileges temporarily, or completely dropping privileges so
- that they will never be regained again. However, there are
- viable attacks that can occur from both operations. Also
- lowering privileges is not always enough without doing away
- with privileged information.
-
- Note on saved credentials
- -------------------------
-
- Before discussing the details of lowering credentials properly,
- the saved credential set needs to be elaborated upon. The saved
- credential set is initialized to the effective credentials of
- the process at the time of its execution. So if the
- process-image has a set-id-on-execution (SUID) or
- set-group-id-on-execution (SGID) bit set, the saved credentials
- will match that credential. This is very useful if the program
- wishes to temporarily drop its effective credentials and then
- regain them.
-
- Lowering privileges temporarily entails changing one of the
- credential sets, usually the effective credentials because they
- are most often checked by the kernel. The seteuid() and
- setegid() system calls allow a process to set its effective
- credentials to its real credentials or its saved credentials.
- This is where the switching between the two credential sets
- becomes very useful. A SUID or SGID process can change its
- effective credentials to its real credentials, which are
- inherited from the parent process, and then switch them back to
- its saved credentials which it inherits from the SUID or SGID
- file permission. In doing so the SUID or SGID program is
- toggling its privileges between its caller and the
- process-image owner.
-
- Because a process cannot get its saved credentials via any
- system call, it is recommended to do a geteuid() and getegid()
- at the beginning of execution and store them internally. This
- works because the saved credentials are an exact copy of the
- effective credentials at the start of a process' execution.
- This will work: saved_uid = geteuid(); saved_gid = getegid();
-
- To change effective credentials to the saved credentials do a
- setegid(saved_gid); seteuid(saved_uid); Now to switch them back
- to match the real credentials do a setegid(getgid());
- seteuid(getuid); Simple and straight forward.
-
- The second method of applying the least privilege principle is
- to completely drop privileges and never regain them again.
- Recall the chfn example mentioned in question 3.2? It would
- have to drop the privileges in its child process completely
- because it gave the user control of the child process. This is
- done by calling setgid() and then setuid(). A common mistake is
- to drop the user ID first, and this will fail if the process is
- relying on the fact that it has root privileges!
-
- There are, as mentioned earlier, viable attacks. The first is
- the signal attack. BSD derived operating systems allow a
- process to send a signal to another process if:
-
- The real user ID of process A is that of the root user.
-
- The real user ID of process A matches the real user ID of
- process B.
-
- The effective user ID of process A matches the effective
- user ID of process B.
-
- The real user ID of process A matches the effective user ID
- of process B.
-
- The effective user ID of process A matches the real user ID
- of process B.
-
- Both processes share the same session ID.
-
- With those semantics it is obvious that if a process lowered
- its effective credentials to that of the user, he would be able
- to send it a signal. In the event that the process begins to
- run with the same real credentials as the user (all SUID or
- SGID processes start out this way), it should change its
- credentials if it expects to trust signals. Keep in mind that
- by lowering its effective credentials to that of the user's
- real credentials it _is_ susceptible. This access check on
- signals is quite a mishmash. Also, change the session ID via
- setsid().
-
- In April 1998, a Bugtraq posting discussed the circumvention of
- a protection scheme employed by implementations of the BSD ping
- utility (Sanfilippo 1998) The ping utility would use the alarm
- routine to synchronize the periodical sending of Internet
- Control Message Protocol (ICMP) echo requests to a remote host,
- and would not allow the normal user to send requests repeatedly
- in a flooding manner. The protection scheme was simply there to
- prevent abusive users from flooding other hosts with a large
- number of ICMP echo requests. The normal user, of course,
- cannot send an ICMP packet because performing this task
- requires the use of a raw socket. Only the root user can open a
- raw socket because of the security implications associated with
- raw network access -- receiving incoming packets rawly from the
- network, and sending raw packets into the network. Thus the
- ping utility is normally installed as SUID to root. The
- technique Sanfilippo used to get around ping's security
- mechanism was to constantly send the SIGALRM signal to it,
- subverting the protection scheme it attempted to implement.
- Since the alarm routine would schedule an occurrence of SIGALRM
- after a specified interval, the ping utility would have a
- signal handler for it, that sends the ICMP echo request.
- Obviously the process may not install handlers and act on them
- blindly if an attacker can trigger the signal handlers.
-
- Some UNIX flavors support the SA_SIGINFO option that can set
- when setting the signal handler via 'sigaction'. This passes
- the handler additional information with regards to who sent the
- signal, and whether or not it is kernel generated. Another
- method is by using internal sanity checks. In the case of
- 'ping' this could have been done by simply keeping track of the
- time that passed in between signals being generated and not
- honoring them unless a sufficient amount of time had passed.
-
- However, a worse case would be a SIGTERM or SIGKILL that halts
- a process when it is in between a critical state. In the case
- of 'chfn' it would be downright despicable of a user to halt it
- just as it was writing out the new password file. If a process
- is in an "unclean state" it should not allow itself to be
- halted by an attacker and retain higher privileges untill the
- point whence it can afford to be halted.
-
- A common mistake is to assume that a process with lowered
- credentials is no longer a security hazard. In fact it just
- might be, even with the previous attacks accounted for.
-
- A well known, but ancient, technique of getting the password
- file from an old SunOS box was to cause its ftp daemon to dump
- core. Similar security holes were later reported (Temmingh
- 1997). If a privileged process reads the password database into
- memory and is then caused to dump core because of a signal
- attack, the core image may hold a copy of the password file
- which is then easily readable by the attacker. But cleaning up
- internal memory may not be enough. A security hole was found on
- OpenBSD's chpass utility with file descriptor leakage (Network
- Associates Inc. 1998). The child process was passed a
- privileged file descriptor because the descriptor was never
- properly closed before giving the user control over the
- process.
-
- Finally, process tracing attacks may take place. FreeBSD, and
- NetBSD both allow a process to trace any process with a
- matching real user ID. Tracing implies complete control over
- the process, including the file descriptors, memory, and
- executable instructions etc; however, a process may not be
- traced if it is SUID or SGID.
-
- Here's a check list for lowering real and effective
- credentials:
-
- Lowering Effective Credentials
- ------------------------------
-
- The process should not have any cleaning up to do. The
- state of external objects should be in a form that is
- suitable for reuse. This includes lock files, updates to
- databases, and even temporary files.
-
- All signal handlers that may be triggered should not be
- trusted; they must be validated for authenticity.
-
- All privileged information held in the process memory
- should be cleared so that a core dump will not contain them
- (don't just free up dynamic privileged memory, clean it out
- before freeing).
-
- Lowering Real Credentials:
- --------------------------
-
- Previous steps must be followed as well. Additional steps take
- into account the process tracing attacks which are not viable
- on all systems.
-
- Privileged information may not be held by the process. This
- includes file descriptors or sockets referencing privileged
- information.
-
- The effective credentials should be dropped to the real
- credentials as well, since a process that is traced can be
- forced to execute arbitrary code under this effective
- credential.
-
- 4) Local Process Interaction:
- -----------------------------
-
- 4.1) What is process attribute inheritance? Or why should I not
- write SUID/SGID programs?
-
- ----------------------------------------------------------------
-
-
- Process attribute inheritance (AFAIK a term I coined), is when
- a child process inherits attributes from the parent process'
- environment. I did see this referred to as "state variables",
- but I forgot by who and all searching has led nowhere. The
- problems with process attribute inheritance were fore shadowed
- by the 'ping' security hole mentioned in question 3.3, as well
- as the OpenBSD 'chpass' hole mentioned in that section.
-
- A child process is an exact copy of its parent except for the
- process ID and the parent process ID. These change for obvious
- reasons. However, all other attributes are the copied with the
- exception of file descriptors. File descriptors, however, are
- shared. (For a more exhaustive explanation see Stevens 1992).
-
- A process is executed after a call to execve() or one of the
- other routines in its family. This system call filters out many
- of the process attributes, but lets some through. This is
- considered a UNIX "feature" and is relied upon by daemons such
- as inetd. Keep in mind that a SUID process is a child that has
- been execve()'d, so it does inherit these attributes. Before I
- present a list of process attributes (albeit probably an
- incomplete list), some known security holes will be discussed
- to illustrate the types of attacks that can occur (Bishop
- 1986).
-
- A post was made to Bugtraq that discussed a weakness in a
- popular Mail User Agent package elm because it trusted an
- environment (Jensen 1994) variable. An autoreply utility was
- packaged with elm that would run with special privileges, and
- perform its own internal checks to prevent exploitation by the
- user. One of the checks included making sure a user did have
- read access to an arbitrary file before allowing him to read it
- (can you see what's wrong with this picture?). If the full path
- to the file was not specified, the utility simply prepended
- whatever was in the HOME environment variable, and opened the
- file for reading, without performing any checks. This allowed
- users to read files with the same privileges as the autoreply
- process. The mistake was to assume that environment variables
- can be trusted for valid information, and that the files in a
- user's home directory are his to read. Both these assumptions
- are false. Environment variables are inherited from a parent
- process, and thus can contain arbitrary information. The
- attacker can manipulate environment variables before forking
- the child process. It is also not true that the user would have
- access to the files in his home directory, necessarily. This
- was a tragic case of giving trust to information that can be
- manipulated by an attacker.
-
- In December 1993, Sun Microsystems released a security
- bulletin, which among other subjects brought up a weakness in
- the modload and loadmod system utilities. The weakness was
- trusting the Internal Field Separator (IFS) environment
- variable. Since the shell would use the IFS to split the
- contents of variables after they are expanded, the attacker can
- specify how the contents are split. A path name such as
- "/bin/cat" , could indeed cause the file "bin" to be executed
- if the IFS is set to '/'. This is because the character '/'
- would be recognized as a field to separate the other strings in
- the variable. Since both these utilities would call upon a
- shell during their execution, the attacker could arbitrarily
- trick the utilities to run his process-images with their
- privileges by modifying the IFS variable. We might think that
- shells should not make use of the IFS variable if the shell is
- not run in interactive mode. This is not a solution, since this
- only canvases the problem of passing down harmful process
- attribute. The solution is not to pass the variable in the
- first place. If the aforementioned utility would not have
- called a shell, it may still have encountered problems with
- other child processes. For example the LD_PRELOAD environment
- variable is used by the run-time linker to load code from any
- shared library the variable specifies. Although the run-time
- linker will ignore such environment variables for SUID or SGID
- processes, the child process of a privileged process may
- inherit them nonetheless and not have such protection. Since
- the child process in turn inherits its parent's privileges, the
- parent is effectively compromised through the child process. So
- remember, the SUID process may have children that are passed
- down harmful environment variables that would not affect the
- SUID program necessarily but affect its children.
-
- At this point I must concede that there may very well be
- implementations of run-time linkers (read: haven't done the
- research yet) that do not make the mistake of using the
- LD_PRELOAD variable even in the child process of a SUID or SGID
- process. Nonetheless, why risk it on an old box?
-
- Finally a reminder of the OpenBSD chpass hole, and the
- descriptor leak. If you haven't read it in section 3.3, go and
- read it.
-
- Thus four types of attacks are viable:
-
- Child process trusts process attribute to contain valid
- information. (elm hole)
-
- The process attribute affects the child process directly.
- (ping hole)
-
- A process inherits an attribute and passes it down to a
- child process that is affected by it. This is the same as
- the second attack, but it is the child process of the
- secure process that is affected. (or the grandchild of the
- attacker). (LD_PRELOAD attack)
-
- The child process of the secure process is passed an
- attribute containing privileged information. (chpass hole)
-
- Now for the list of process attributes and how to go about
- avoiding any security holes.
-
- Credentials:
-
- Just a review of section 3. Processes running with the same
- credentials, or similar (see section 3!) can be attacked by
- process tracing, or sent signals that affect them.
-
- File Descriptors:
-
- The 'chpass' security hole had a file descriptor leak. A
- quick and easy way of avoiding file descriptor leaks is by
- setting the FD_CLOEXEC flag on the descriptor (again, see
- Stevens 1992 as he discusses this rather well). But that's
- not the end of it. In 1998 the OpenBSD team released a
- patch for OpenBSD which would not allow a SUID or SGID
- program from inheriting empty file descriptors in the first
- three slots. It would instead set them pointing to
- /dev/null. Theo deRaadt mentioned to me one of the problems
- that could occur: if the inherited descriptor would be
- opened as a raw socket, and error reporting by the standard
- C library (standard error) would be sent through it, bogus
- packets could be sent to the socket. Although he did
- mention for other reasons programs such as traceroute were
- not susceptible. As a workaround for systems without this
- security feature, doing a stat on the first three file
- descriptors to check their availability and opening them to
- "/dev/null" should do. It just adds bloat to your code, and
- should really be handled by the kernel.
-
- Environment Variables:
-
- Don't trust environment variables to contain valid
- information. In the case of the above mentioned 'elm' hole,
- it would have been wiser to look up the home directory in
- the password database. Another more subtle issue is not
- placing privileged information in an environment variable
- (Smith 1998). Specifically, a security hole related to
- FreeBSD's 'ps' utility. The utility would allow users to
- view another process' environment variables. Consequently
- applications like pppd that accepted passwords via
- environment variables became vulnerable to unauthorized
- release of privileged information attacks. In fact, the
- hole was not related to 'ps' if you think about it
- critically. The application that places privileged
- information in the environment variable is at fault.
-
- Finally comes the security hole related to having an
- environment variable affect an external program. IFS and
- LD_PRELOAD, as discussed previously, are viable environment
- variables, but a secure program should remove all
- environment variables except the ones it chooses to use and
- knows will not affect it. A good idea is to get rid of
- every environment variable you don't need and keep the ones
- you know are useful and actually have a use for.
-
- File Mode Creation Mask:
-
- Although it is very common for a robust program to reset
- its file mode creation mask by calling umask(), it should
- still be noted as a viable security concern. An attacker
- can pass a mask that would affect the file permissions of
- files created by open() and mkdir(). Resetting the mask to
- 0 suffices to prevent a file mode creation mask attack.
-
- Working and Root Directories
-
- Both the current working directory, and the root directory
- are inherited from the parent process. The working
- directory affects file system calls if they are not passed
- a full path name. This can be made into an attack. Thus it
- is advisable to both set the current working directory, and
- use full paths when making file system calls. The root
- directory should not be a concern. Only the root user can
- change the root directory.
-
- Resource Limits
-
- The setrlimit() system call allows a process to set soft or
- hard limits on its consumption of resources. When a process
- reaches its soft limit a signal is sent depending on which
- limit is reached. SIGSEV for the maximum stack size,
- SIGXFSZ for an I/O operation that exceeded a file size
- limit etc. The list is left till the section on resource
- limits, but the signals if not handled will result in the
- process being terminated. A careful attacker may trigger a
- denial of service attack where the process is terminated in
- the middle of performing a critical operation. When the
- hard limit is reached, the process is prevented from
- executing any further. The soft limits may be raised or
- lowered at the process' own discretion. Thus by setting all
- limits to infinity, the process can relieve itself of any
- resource limit attacks. However, the hard limit can be
- lowered by a normal user, but cannot be raised except by
- root. A viable attack is to lower the hard resource limits,
- and have the child process choke from underneath. The most
- obvious solution is not to begin execution if the hard
- limits are too low, and to heighten the soft limits to
- infinity. Raising the soft limits over the hard limits will
- not work. Thus the process will begin by specifying how
- much of the individual resources it requires, and if the
- setrlimit() system call returns an error it will not begin
- execution as to avoid resource starvation. This is not very
- helpful though, and better treatment of resource limits is
- given in its own section below.
-
- Scheduling Priority
-
- The scheduling priority on a process can be modified by a
- call to nice() or setpriority(). This is usually done to
- tell the scheduler how important the process is. A very low
- priority may cause the process to execute slower, which can
- aid an attacker if he is attempting to exploit a race
- condition.The semantics of setpriority() requires the user
- to have an effective user ID matching the real or effective
- user ID of the peer process. So this may not necessarily be
- inherited. However, the priority of a process can only help
- an attacker exploit a race condition more easily. It does
- not really constitute a denial of resource attack unless
- the process has time constraints. Regardless of the speed
- of a process, a race condition can always be exploited.
- Even with the element of luck, or by slowing down the
- system as a whole. Race conditions need to be eliminated
- and not made harder to exploit. Keep an eye out for this
- scheduling priority in the rare case that it actually does
- matter.
-
- Interval Timers
-
- Three interval timers that can be manipulated by the
- setitimer() system call. The alarm facility is usually
- wrapped around a call to setitimer(). Since the interval
- timers are inherited, a parent process could set a timer to
- send its child process SIGALRM, SIGVTALRM or the SIGPROF
- signal. These could be used to either subvert a program if
- it were to handle them, or terminate it. These signals
- should be ignored at the beginning of the process'
- execution or the timers should be reset.
-
- Signal Handlers
-
- Although all signal handlers are reset to their defaults,
- blocked signals remain blocked and so do ignored signals.
- This could be a problem if our program design is built
- around receiving a signal before carrying on, and assumes
- it is not blocked or ignored. Resetting the state of the
- signal mask, and resetting signal handlers should also be
- done without any preconceptions of default settings.
-
- With all of this SUID/SGID programming is daunting at best. A
- better technique (proposed by Thomas Ptacek on the newsgroup)
- would be to use a server-client model where the server is
- privileged but does not inherit the environment of its parent
- process -- a would be attacker. That way the client runs with
- no privileges, connects to the privileged server and passes the
- relevant information through the IPC channel.
-
- 4.2) How can I limit access to a SUID/SGID process-image
- safely?
-
- ----------------------------------------------------------------
-
-
- The question may seem vague but sometimes it would seem
- attractive to have a SUID process that is only executable by a
- particular set of users. Some time ago I implemented a
- distributed network monitoring package that had java clients
- talk to it remotely, and sniffers running on different servers
- (a very ambitious undertaking). The actual servers where run
- under a special group called "sly" that would in turn have
- access to a SUID process-image to do all the sniffing. The
- child process ran as root, but could only be executed by users
- in the group "sly."
-
- At first this looks good. The actual server does not run with
- special privileges, and it would seem that if it got exploited
- the attacker would not gain root privileges. However, he would
- gain privileges for the group "sly" that would let him sniff
- the local network. If he was then able to exploit the sniffer,
- he would gain root privileges. But he needs to exploit the
- server to the point of executing arbitrary code on the machine.
- Creating a file, or tricking it into sending privileged
- information would not equate to gaining the privileges of group
- "sly" necessarily. So this does not lessen the need for secure
- code, but it _could_ in the long run lessen the chances of
- complete compromise. I'm going to call this technique, at the
- risk of coining yet another term, privilege segmentation. The
- attacker may gain privileges to a specific group but has more
- work to do in order to gain higher privileges.
-
- Fair warning that security via "chance" or "hope" is not good.
- I don't particularly like hearing about "risk management," and
- the above technique is just that: risk management.
-
- 4.3) How do I authenticate a parent process?
- --------------------------------------------
-
- Since the child process inherits the parent's real user ID, a
- call to getuid() does the trick. Unfortunately due to a
- misconception, some programmers are led to believe that
- getuid() is not sufficient. This stems from the thinking that
- if a user managed in exploiting a SUID process into running
- another process, the child would have a real user ID matching
- the parent process' effective user ID. This is not true,
- because the real user ID keeps propagating from parent to child
- regardless of the SUID feature. As mentioned in 2.1, the child
- process inherits the credentials directly, a perfect copy with
- the exception of the effective credentials if the SGID or SUID
- feature. The saved credentials are also reset. But this
- exception does not extend to the real credentials which are
- directly inherited.
-
- However, if the exploited SUID process was to change its real
- user ID to match its effective user ID, which is easily done
- with setuid(), then getuid() is not sufficient. There is a
- logical fallacy here: if the parent process has already been
- exploited to the point where the attacker can cause it to
- switch credentials what's the point in faking it anymore?
- Nonetheless, additional steps can be taken but not portably. On
- systems where login information is stored in the kernel, and
- not on the file system, by setlogin(), getlogin() will always
- return the username associated with the session. [ FreeBSD
- stores login information in kernel. ]
-
- On OpenBSD, and FreeBSD the issetugid() system calls can be
- used to find out if the current process is a SUID or GUID
- process. This propagation continues unless a child process
- clears all its privileges, to quote the OpenBSD man page "uid
- != euid or gid != egid". So this system call may be used in
- conjunction with getuid to be even more paranoid.
-
- A good suggestion is to do a getuid(), check getlogin() if the
- information is stored in the kernel, and finally do a
- issetugid(). If all tests pass, you know you are talking to the
- Real McCoy. In saying that, caution should not be thrown to the
- wind. Using passwords, cookies,
- insert-fancy-authentication-mechanism-here etc. is always
- recommended, but the previous approach is the more light weight
- kernel supported method.
-
- 4.4) How do I authenticate a non-parent process?
- ------------------------------------------------
-
- [ I could use writing on SO_PEERCRED (Linux) doors (Solaris)
- and LOCAL_CREDS (NetBSD). Also I have some example code for the
- techniques discussed below. If you tackle the any of the issues
- above, you would be a very nice contributor to provide example
- source. Also this is advanced stuff so I'll elaborate more when
- I fix it up]
-
- It is possible to authenticate processes via IPC channels
- (Bernstein 1999). However the methods differ on different UNIX
- flavors making it a very non-portable mess to write.
-
- BSD derived systems support the concept of access rights
- (Stevens 1990). The facility allows a process to pass a file
- descriptor through a UNIX domain socket, and with a small hack
- it can be used to authenticate a local process. The term hack
- is only used because the facility was not intended for
- authentication. However, if the client sends a descriptor
- referencing a file that has read permissions only for its
- owner,the receiver knows the sender is the owner. Thus the file
- acts as an identifier. However, on systems where a user may
- give away files with chown() this method cannot be used. The
- attacker can simply create a file with read permissions only
- for himself, open it, and then chown it to another user.
- Fortunately this is a System V "feature," and on many systems
- can be turned off as a kernel configuration option.
-
- A similar technique is found under System V derived systems.
- This is done by receiving file descriptors via a STREAMS file.
- Only the file descriptor is discarded because the UID is passed
- along with it. This is done by using an ioctl call with the
- I_SENDFD and I_RECVFD flags on a streams file used as an IPC
- channel. This technique does not suffer from the chown attack
- because the credentials are passed _along_ with the descriptor.
-
- BSD/OS, FreeBSD and other BSD derived operating systems also
- have SCM_CREDS that sends credential information through a UNIX
- domain socket. [ Ok, someone point me to some standard that
- documents the semantics. Every BSD camp is doing it differently
- ":( ]
-
- 5) Using The File System Securely
- ---------------------------------
-
- [ The first contributor to find a better solution to 5.2 gets a
- donut ]
-
- Sadly too many past security holes show that the average programmer
- fails to note that the file system is a database with links
- pointing to resources, and that filenames act only as identifiers.
- Indeed that is how we get race condition attacks, and symlink
- attacks. Both are given treatment below, but keep in mind that the
- principles are open to other databases that follow the same model
- as the file system. In particular race conditions may occur in
- non-file-system related operations.
-
- 5.1) How do I avoid race condition attacks?
- -------------------------------------------
-
- A race condition occurs when two or more operations occur in an
- undefined manner (McKusick et al. 1996). Specifically in file
- system races the attacker attempts to change the state of the
- file system in between two file system operations on the part of
- the program. Usually the program expects the two operations to
- apply to the same file, or expects the information retrieved to
- be the same. If the file operations are not atomic, or do not
- reference the same file this cannot be guaranteed without proper
- care. As an added note see Bishop 1996 for a more exhaustive and
- but more theoretical discussion.
-
- Solaris 2.x's 'ps' utility had a security hole that was caused by
- a race condition (Chasin 1995). The utility would open a
- temporary file, and then use the chown() system call with the
- file's full path to change its ownership to root. This was easily
- exploitable by slowing the system down, finding the file created,
- deleting it, and then slipping in a new file with a mode of 1777
- (world writable with SUID bit). After the file was created with
- that mode and chowned to root, the attacker simply copies a shell
- into the file. Viola, instant root shell. (The exploit itself
- made use of symlinks to slip in the new file, but I'm leaving the
- concept of symlinks untill the next 5.2)
-
- At first glance to the less perceptive reader it may seem that if
- the original file was not created world writable the attacker
- could not delete it. Well it was not world writable and he could.
- The file was created under the temporary directory (usually
- "/var/tmp" or "/tmp") which had world writable permissions.
- Global temporary directories are setup this way or they aren't
- usable, hence the world global. It's a completely different issue
- to argue whether having global temporary directories is a good
- idea. I won't be discussing philosophical issues here, let's
- stick to the facts (for a similar security hole see Hull 1996).
-
- The problem was that the second operation used the file name and
- not the file descriptor. If a call to fchown() would have been
- used on the file descriptor returned from the original open()
- operation, the security hole would have been avoided. File names
- are _not_ unique. The file name "/tmp/foo" is really just an
- entry in the directory "/tmp". Directories are special files. If
- an attacker can create, and delete files from a directory the
- program cannot trust file names. Instead it should use file
- descriptors to perform its operations.
-
- There are other race conditions that can occur. Using stat() and
- instead of fstat(). Using access() and thinking that the
- information will persist untill the next few lines of code. It
- will not so don't expect it to. The only way to make sure the
- file permissions will not change, and that you have the file you
- want is to fstat() after an open(). See below for a treatment
- toward opening files safely.
-
- 5.2) How do I create/open files safely?
- ---------------------------------------
-
- A symbolic link is a file that stores a pathname to another file.
- The kernel just uses the path to reference the file. It is a
- convenient way to keep links to files which may not necessarily
- always exist. Hard links on the other hand create a new link to the
- file (see McKusick et al. 1996 [ page 251]).
-
- A security hole reported for SUN's license manager stemmed from the
- creation of a file without checking for symbolic links (or soft
- links) (Eriksson 1996). An open() call was made to either create
- the file if it did not exist, or open it if it did exist. The
- problem with symbolic link is that an open call will follow it and
- not consider the link to constitute a created file. So if you had
- "/tmp/foo" symlinked to "/.rhosts" (or "/root/.rhosts" depending on
- your cultural background), the latter file would be transparently
- opened. The license manager seemed to have used the O_CREAT flag
- with the open call making it create the file if it did not exist.
- To make matters worse, it created the file with world writable
- permissions. Since it ran as root, the ".rhosts" file could be
- created, written to, and root privileges attained. I'll leave it as
- an exercise to the reader to work out how a world writable
- ".rhosts" file can be used to get root privileges. (Back in those
- days a world writable ".rhosts" was OK on the part of rlogind)
-
- There is a problem here that relates to the previous discussion on
- race conditions. A program needs to both check for the existence of
- a file, and make sure it's pathname is not the result of a symbolic
- link. At first the O_EXCL flag comes to mind. If used with O_CREAT
- it will return an error if the file exists. Sadly, the UNIX98
- standard does not define behavior for symbolic links and O_EXCL.
- FreeBSD 2.2.7 does, to quote its man page:
-
- "If O_EXCL is set and the last component of the pathname is a
- symbolic link, open() will fail even if the symbolic link points to
- a non-existent name."
-
- The astute reader will note that this only relates to files with
- the "last component" meaning the last part of the path. Also, to
- rely on semantics that are not standard is just asking for trouble.
- I strongly suggest inserting a check at compile time to look for
- these semantics, and steadfastly refuse to compile if they don't
- exist. For the sake of absolute security, the discussion will
- continue without taking these semantics into consideration.
-
- One of the work arounds is to create a file with write only
- permissions for the program's real user ID (we'll consider it to be
- root for the sake of discussion). Then an fstat() can be made and
- the program will know the full path to the file it has opened. If
- it is the correct file, go about business as usual, fchmod() if you
- want as well. However, if it is the wrong file it needs to be
- deleted. Here it comes: there's no funlink(), or at least none on
- any standard or box that I've seen.
-
- The reader may claim that if the file being deleted is a symbolic
- link, then the symbolic link will be unlinked and not the actual
- file. This is true, but what if the symbolic link was between
- directories and not the last component. Consider the path
- "/usr/foo/bar/footest" to the file "footest" now make a symbolic
- link with "/usr/foo2" pointing to "/usr/foo/bar." Now unlink() with
- "/usr/foo2/footest", and "/usr/foo/bar/footest" will be deleted.
- Since the directory is a symbolic link, and not the last component,
- the symbolic link is unaffected by the unlink() call.
-
- So there's no way to safely delete files. How do you like them
- apples? If it is ok to leave files around, then this work around
- will do. However, let's continue, yet again, for the sake of
- absolute security.
-
- A special directory can be created. It would have permissions that
- allow only the process to read, write, and create files in it. This
- is probably the best solution. The global tmp directory won't work
- because all the other users have access to it. Directories created
- by the program for itself seems to be the only solution. No
- symbolic links can linked into the directories, so no trickery can
- take place. Only this means a human has to create the special
- directory, because as we have seen it's impossible to completely
- avoid symbolic link attacks. This is by all means possible,
- consider using directories in /var that are owned and accessible by
- the secure process only.
-
- 8) Bibliography
- ---------------
-
- Chasin, Scott "BUGTRAQ ALERT: Solaris 2.x vulnerability" Online
- posting. 14. Aug. 1995. Bugtraq.
-
- Bernstein, Dan "Secure Interprocess Communication" 1998. <URL:
- //koobera.math.uic.edu/www/docs/secureipc.html>
-
- Bernstein, Dan "Re: A thought on TCP SYN attacks" Online posting.
- 26 Sept. 1996. SYN-Cookies Mailing List.
-
- Bishop, Matt "How to write a setuid program" login 12(1) Jan/Feb
- 1986.
-
- Bishop, Matt "Checking for Race Conditions in File Accesses," M.
- Bishop and M. Dilger, Computing Systems 9(2) (Spring 1996) pp.
- 131-152.
-
- daemon9, route, infinity "Project Neptune" Phrack, Vol.7, No. 48,
- July 1996, [ File 13 of 18 ]
-
- Der Mouse "Re: Tar "features"" Online posting. 25 Sept. 1998.
- Bugtraq.
-
- Eriksson, Joel "License Manager's lockfiles (Solaris 2.5.1)"
- Online posting. 12 Oct. 1998. Bugtraq.
-
- Hull, Gregory "r00t advisory -- sol2.5 su(1M) vulnerability"
- Online posting. 26 Aug. 1996.
-
- Harrison, Roger "License Manager's lockfiles (Solaris 2.5.1)"
- Online posting. 23 Oct. 1998. Bugtraq
-
- Jensen, Geir Inge "Another autoreply security hole" Online
- posting, 12 Mar. 1994. Bugtraq.
-
- Network Associates Inc. "Network Associates Inc. Advisory
- (OpenBSD)" Online posting. 10 Aug. 1998. Bugtraq.
-
- plaguez, shegget "XFree86 insecurity" Online posting. 21 Nov.
- 1997. Bugtraq.
-
- Saltzer, J.H., and M.D. Schroeder, "The Protection of Information
- in Computer Systems," Proc. IEEE, Vol. 63, No. 9, Sept. 1975, pp.
- 1278-1308.
-
- Sanfilippo, Salvatore "pingflood.c" Online posting. 9 Apr. 1998.
- Bugtraq.
-
- Schenk, Eric "A thought on TCP SYN attacks" Online posting. 25
- Sept. 1996. SYN-Cookies Mailing List.
-
- Stevens, Richard W. "UNIX Network Programming" New Jersey,
- Prentice Hall, 1990.
-
- Stevens, Richard W. "Advanced Programming In The UNIX
- Environment" Reading, Massachusetts, Addison-Wesley, 1992.
-
- Smith, Ben "ps(1) for freebsd." Online posting. 12 Aug. 1998.
- Bugtraq.
-
- Tarreau, William "Tar "features"" Online posting. 22 Sept.
- 1998. Bugtraq.
-
- Temmingh, Roelof W "FreeBSD rlogin and coredumps" Online
- posting. 17 Feb. 1997. Bugtraq
-
- Wall, Larry and Schwartz, Randal L. "Programming Perl" :
- Sebastopol, California : O'Reilly And Associates, 1992.
-
- Zalewski, Michal "ipop3d (x2) / pine (x2) / Linux kernel (x2) /
- Midnight Commander (x2)" Online posting. 7, March 1999.
- Bugtraq.
-
- 9) List of Contributors
- -----------------------
-
- Thamer Al-Herbish <shadows@whitefang.com>
-
- "Youth, Nature, and relenting Jove,
- To keep my lamp _in_ strongly strove,
- But Romanelli was so stout,
- He beat all three -- _and blew it out_."
-
- -- George Gordon Byron "My Epitaph" From "Occasional Pieces"
-
-